// ###########################################################################################################################
// Primitive objects in the root System namespace.
// ###########################################################################################################################

module DreamSpace.System {
    // =======================================================================================================================

    /** Returns a new basic object instance.
    * @param {any} value Specifying a defined value for this objects causes it to return the value for 'valueOf' and 'toString'.
    * @param {boolean} makePrivate If false (default) a property named '__value' is created to store the value. If true, the
    *                              value is kept private by wrapping it in a closure (less efficient [creates wrapper
    *                              functions]).  This may change when 'Object.defineProperty()' becomes more widely supported.
    */
    export declare function Object(value?: any, makePrivate?: boolean): Object.$Type;
    AppDomain.registerType("Object", [DreamSpace, System]);
    /** The base type for all DreamSpace objects. */
    export module Object {
        /** Returns the type name for an object instance registered with '{AppDomain}.registerType()'.  If the object does not have
        * type information, and the object is a function, then an attempt is made to pull the function name (if one exists).
        * Note: This function returns the type name ONLY (not the FULL type name [no namespace path]).
        * Note: The name will be undefined if a type name cannot be determined.
        * @param {{}} object (optional) If specified, returns the type name of the given object registered
        * using '{AppDomain}.registerType()', or the constructor function name.
        * @param {boolean} cacheTypeName (optional) If true (default), the name is cached using the 'ITypeInfo' interface via the '$__name' property.
        * This helps to speed up future calls.
        */
        export function getTypeName(object?: {}, cacheTypeName?: boolean): string {
            if (object === void 0 || object === null) return void 0;
            typeInfo = <ITypeInfo>object;
            if (typeInfo.$__name === void 0 || typeInfo.$__name === null) {
                var typeInfo = <ITypeInfo><any>object.constructor;
                if (typeInfo.$__name === void 0 || typeInfo.$__name === null) {
                    typeInfo.$__name = Utilities.getFunctionName(object.constructor);
                    return typeInfo.$__name;
                }
                else return typeInfo.$__name;
            }
            else return typeInfo.$__name;
        }

        /** The parent module (object) that contains the type (function instance).
        * Note: This value is only set on types registered using '{AppDomain}.registerType()'.
        */
        export declare var $__parent: ITypeInfo;

        /** Returns the name of this type.
        * Note: This is the object type name taken from the constructor (if one exists), and is not the FULL type name (no namespace).
        * Note: This value is only set on types registered using '{AppDomain}.registerType()'.
        */
        export declare var $__name: string;

        /** Returns the full name of this type (includes the namespace).
        * Note: This value is only set on types registered using '{AppDomain}.registerType()'.
        */
        export declare var $__fullname: string;

        /** Returns true if the given object is empty. */
        export function isEmpty(obj): boolean {
            if (obj === void 0 || obj === null) return true;
            // (note 'DontEnum flag' enumeration bug in IE<9 [on toString, valueOf, etc.])
            for (var key in obj)
                if (Object.prototype.hasOwnProperty.call(obj, key)) return false;
            return true;
        }

        /**
        * Returns the prototype of an object.
        * @param o The object that references the prototype.
        */
        export declare function getPrototypeOf(o: any): any;

        /**
        * Gets the own property descriptor of the specified object.
        * An own property descriptor is one that is defined directly on the object and is not inherited from the object's prototype.
        * @param o Object that contains the property.
        * @param p Name of the property.
        */
        export declare function getOwnPropertyDescriptor(o: any, p: string): PropertyDescriptor;

        /**
        * Returns the names of the own properties of an object. The own properties of an object are those that are defined directly
        * on that object, and are not inherited from the object's prototype. The properties of an object include both fields (objects) and functions.
        * @param o Object that contains the own properties.
        */
        export declare function getOwnPropertyNames(o: any): string[];

        /**
        * Creates an object that has the specified prototype, and that optionally contains specified properties.
        * @param o Object to use as a prototype. May be null
        * @param properties JavaScript object that contains one or more property descriptors.
        */
        export declare function create(o: any, properties?: PropertyDescriptorMap): any;

        /**
        * Adds a property to an object, or modifies attributes of an existing property.
        * @param o Object on which to add or modify the property. This can be a native JavaScript object (that is, a user-defined object or a built in object) or a DOM object.
        * @param p The property name.
        * @param attributes Descriptor for the property. It can be for a data property or an accessor property.
        */
        export declare function defineProperty(o: any, p: string, attributes: PropertyDescriptor): any;

        /**
        * Adds one or more properties to an object, and/or modifies attributes of existing properties.
        * @param o Object on which to add or modify the properties. This can be a native JavaScript object or a DOM object.
        * @param properties JavaScript object that contains one or more descriptor objects. Each descriptor object describes a data property or an accessor property.
        */
        export declare function defineProperties(o: any, properties: PropertyDescriptorMap): any;

        /**
        * Prevents the modification of attributes of existing properties, and prevents the addition of new properties.
        * @param o Object on which to lock the attributes.
        */
        export declare function seal(o: any): any;

        /**
        * Prevents the modification of existing property attributes and values, and prevents the addition of new properties.
        * @param o Object on which to lock the attributes.
        */
        export declare function freeze(o: any): any;

        /**
        * Prevents the addition of new properties to an object.
        * @param o Object to make non-extensible.
        */
        export declare function preventExtensions(o: any): any;

        /**
        * Returns true if existing property attributes cannot be modified in an object and new properties cannot be added to the object.
        * @param o Object to test.
        */
        export declare function isSealed(o: any): boolean;

        /**
        * Returns true if existing property attributes and values cannot be modified in an object, and new properties cannot be added to the object.
        * @param o Object to test.
        */
        export declare function isFrozen(o: any): boolean;

        /**
        * Returns a value that indicates whether new properties can be added to an object.
        * @param o Object to test.
        */
        export declare function isExtensible(o: any): boolean;

        /**
        * Returns the names of the enumerable properties and methods of an object.
        * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
        */
        export declare function keys(o: any): string[];

        export declare class $Type implements NativeTypes.IObject, IDisposable, ISerializable {
            [index: string]: any;

            /** The AppDomain that this object instance belongs to (see 'System.Platform.AppDomain' for more details). */
            __appDomain: AppDomain;

            /** The ID of this object, which is useful for synchronizing across networks (among other things).
            * Internally, all objects have a numbered ID, which is unique across the entire client/server side environment for a
            * single application domain.
            */
            __id: number; // (value is set and maintained by a Collections.IndexedObjectCollcetion instance; see 'DreamSpace.objects' [static collection])

            constructor(value?: any);

            ///** Used in place of the constructor to create a new instance of the underlying object type for a specific domain.
            //* This allows the reuse of disposed objects to prevent garbage collection hits that may cause the application to lag, and 
            //* also makes sure the object is associated with an application domain.
            //* Objects that derive from 'Object' should implement a 'new()' function with the proper signature (usually the same as the
            //* constructor).  This is done by creating a static property on the class called 'new' and setting it to the function returned 
            //* from the 'AppDomain.registerCall()' function.
            //* Note: When creating thousands of objects continually, object disposal (and subsequent cache of the instances) means the GC
            //* doesn't have to keep engaging to clear up the abandoned objects.  While using the "new" operator may be faster than using
            //* "{type}.new()" at first, the application actually becomes very lagged while the GC keeps eventually kicking in.  This is
            //* why DreamSpace objects are cached and reused as much as possible.
            //*/
            //??static new(...args);

            /** Disposes this instance, sets all properties to 'undefined', and calls the constructor again (a complete reset). */
            new: (...args) => Object;

            /** Release the object back into the object pool. */
            dispose(allowRelease?: boolean): void;

            /** Returns the type information for this object instance. */
            getType(): IFunctionInfo;

            /** Serializes the object's '__id' value only. */
            getData(data: SerializedData): void;

            /** Restores the object's '__id' value (only works if '__id' is undefined). */
            setData(data: SerializedData): void;

            /** Returns true if the specified value is equal to this object.
            * The default implementation only compares if the object references are equal.  Derived types should override this
            * with a new more meaningful implementation where necessary.
            */
            equal(value: any): boolean;

            /** Returns a string representation of an object. */
            toString(): string;

            /** Returns a date converted to a string using the current locale. */
            toLocaleString(): string;

            /** Returns the primitive value of the specified object. */
            valueOf(): Object;

            /**
              * Determines whether an object has a property with the specified name. 
              * @param v A property name.
              */
            hasOwnProperty(v: string): boolean;

            /**
              * Determines whether an object exists in another object's prototype chain. 
              * @param v Another object whose prototype chain is to be checked.
              */
            isPrototypeOf(v: Object): boolean;

            /** 
              * Determines whether a specified property is enumerable.
              * @param v A property name.
              */
            propertyIsEnumerable(v: string): boolean;
        }

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        (function () {
            // ... extend the native object and copy over the static properties ...
            var valueOf = function () { return this.__value; };
            var toString = function () { return '' + this; };
            System.Object = <typeof Object><any>function Object(value?: any, makePrivate: boolean = false) {
                if ((<System.Object.$Type>this).__appDomain == void 0)
                    (<System.Object.$Type>this).__appDomain = AppDomain.defaultDomain;
                // ... if a value is given, the behaviour changes to latch onto the value ...
                if (value == void 0) {
                    if (makePrivate) {
                        this.valueOf = function () { return value; };
                        this.toString = function () { return '' + value; };
                    } else {
                        this['__value'] = value;
                        this.valueOf = valueOf;
                        this.toString = toString;
                    }
                }
            };
            // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
            Utilities.extend(System.Object.$Type, global.Array); // (allow array functions to be called on the object! [note: 'length' only supports consecutive array numbers in this case])
            // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
            //??System.Object.new = function () {
            //    throw Exception.error("{object}.new", "You need to register the class/type first: see 'AppDomain.registerClass()'.", this);
            //    // (this function should never be called directly, and should be replaced on classes when defined)
            //};
            System.Object.prototype.new = function (): Object {
                // ... do a dispose and complete wipe ...
                if ((<$Type>this).dispose !== noop)
                    dispose(<$Type>this, false); // 'false' also keeps the app domain (see 'dispose()' below), and only removes it from the "active" list.
                //??if (!this.constructor.new)
                //    throw Exception.error("{object}.new", "You need to register the class/type first: see 'AppDomain.registerClass()'.", this);
                var instance = <Object.$Type>this.constructor.apply(this, arguments);
                instance.__appDomain.objects.addObject(instance);
                delete instance.dispose;
                return instance;
            };
            System.Object.prototype.equal = function (value: any): boolean {
                return this === value;
            }
                // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
                System.Object.prototype.dispose = function dispose(release?: boolean) {
                // ... this should be the final code executed in the disposal chain ...
                var appDomain = (<$Type>this).__appDomain; // (note: may be set to UNDEFINED if this is called from '{AppDomain}.dispose()')
                (<$Type>this).dispose = noop; // (make sure 'appDomain.dispose()' doesn't call back)
                if (appDomain)
                    appDomain.dispose(<Object.$Type>this, release);
            };
            // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
            System.Object.prototype.getType = function getType(): IFunctionInfo {
                if (!(<ITypeInfo>this.constructor).$__name && (<typeof Object>this.constructor).getTypeName)
                    (<typeof Object>this.constructor).getTypeName();
                return <IFunctionInfo>this.constructor;
            };
            System.Object.prototype.getData = function getData(data: SerializedData): void {
            }
            })();

        AppDomain.registerClass(Object);
    }

    // =======================================================================================================================

    /** Returns a new string object instance. 
    * Note: This is a DreamSpace system string object, and not the native JavaScript object. */
    export declare function String<T>(value?: any): String.$Type;
    AppDomain.registerType("String", [DreamSpace, System]);
    /** Allows manipulation and formatting of text strings, including the determination and location of substrings within strings. */
    export module String {
        /** Create a string from a list of Unicode arguments. */
        export declare function fromCharCode(...codes: number[]): string;

        /** Replaces one string with another in a given string.
        * This function is optimized to select the faster method in the current browser. For instance, 'split()+join()' is
        * faster in Chrome, and RegEx based 'replace()' in others.
        */
        export function replace(source: string, replaceWhat: string, replaceWith: string, ignoreCase?: boolean): string {
            // (split+join is faster in some browsers, or very close in speed) http://jsperf.com/split-join-vs-regex-replace-the-raven
            if (typeof source !== 'string') source = "" + source;
            if (typeof replaceWhat !== 'string') replaceWhat = "" + replaceWhat;
            if (typeof replaceWith !== 'string') replaceWith = "" + replaceWith;
            if (ignoreCase)
                return source.replace(new RegExp(Text.RegEx.escapeRegex(replaceWhat), 'gi'), replaceWith);
            else
                if (Browser.type == Browser.BrowserTypes.Chrome)
                    return source.split(replaceWhat).join(replaceWith); // (MUCH faster in Chrome [including Chrome mobile])
                else
                    return source.replace(new RegExp(Text.RegEx.escapeRegex(replaceWhat), 'g'), replaceWith);
        }

        /** Replaces all tags in the given 'html' string with 'tagReplacement' (an empty string by default) and returns the result. */
        export function replaceTags(html: string, tagReplacement?: string): string {
            return html.replace(/<[^<>]*|>[^<>]*?>|>/g, tagReplacement);
        }

        /** Pads a string with given characters to make it a given fixed length. If the string is greater or equal to the
        * specified fixed length, then the request is ignored, and the given string is returned.
        * @param {any} str The string to pad.
        * @param {number} fixedLength The fixed length for the given string (note: a length less than the string length will not truncate it).
        * @param {string} leftPadChar Padding to add to the left side of the string, or null/undefined to ignore. If 'rightPadChar' is also specified, the string becomes centered.
        * @param {string} rightPadChar Padding to add to the right side of the string, or null/undefined to ignore. If 'leftPadChar' is also specified, the string becomes centered.
        */
        export function pad(str: any, fixedLength: number, leftPadChar: string, rightPadChar?: string): string {
            if (str === void 0) str = "";
            if (leftPadChar === void 0 || leftPadChar === null) leftPadChar = "";
            if (rightPadChar === void 0 || rightPadChar === null) rightPadChar = "";

            var s = "" + str, targetLength = fixedLength || 0, remainder = targetLength - s.length,
                lchar = "" + leftPadChar, rchar = "" + rightPadChar,
                i: number, n: number, llen: number, rlen: number, lpad: string = "", rpad: string = "";

            if (remainder == 0 || (!lchar && !rchar)) return str;

            if (lchar && rchar) {
                llen = Math.floor(remainder / 2);
                rlen = targetLength - llen;
            }
            else if (lchar) llen = remainder;
            else if (rchar) rlen = remainder;

            for (i = 0; i < llen; ++i)
                lpad += lchar;

            for (i = 0; i < rlen; ++i)
                rpad += rchar;

            return lpad + s + rpad;
        }

        /** Appends the suffix string to the end of the source string, optionally using a delimiter if the source is not empty.
        * Note: If any argument is not a string, the value is converted into a string.
        */
        export function append(source: string, suffix?: string, delimiter?: string): string {
            if (source === void 0) source = "";
            else if (typeof source != 'string') source = '' + source;
            if (typeof suffix != 'string') suffix = '' + suffix;
            if (typeof delimiter != 'string') delimiter = '' + delimiter;
            if (!source) return suffix;
            return source + delimiter + suffix;
        }

        /** Appends the prefix string to the beginning of the source string, optionally using a delimiter if the source is not empty.
        * Note: If any argument is not a string, the value is converted into a string.
        */
        export function prepend(source: string, prefix?: string, delimiter?: string): string {
            if (source === void 0) source = "";
            else if (typeof source != 'string') source = '' + source;
            if (typeof prefix != 'string') prefix = '' + prefix;
            if (typeof delimiter != 'string') delimiter = '' + delimiter;
            if (!source) return prefix;
            return prefix + delimiter + source;
        }

        export declare class $Type extends Object.$Type implements NativeTypes.IString {
            [index: number]: string;

            constructor(value?: any);

            /** Replaces one string with another in the current string. 
            * This function is optimized to select the faster method in the current browser. For instance, 'split()+join()' is
            * faster in Chrome, and RegEx based 'replace()' in others.
            */
            replaceAll(replaceWhat: string, replaceWith: string, ignoreCase?: boolean): string;

            /** Returns a string representation of a string. */
            toString(): string;

            /**
              * Returns the character at the specified index.
              * @param pos The zero-based index of the desired character.
              */
            charAt(pos: number): string;

            /** 
              * Returns the Unicode value of the character at the specified location.
              * @param index The zero-based index of the desired character. If there is no character at the specified index, NaN is returned.
              */
            charCodeAt(index: number): number;

            /**
              * Returns a string that contains the concatenation of two or more strings.
              * @param strings The strings to append to the end of the string.  
              */
            concat(...strings: string[]): string;

            /**
              * Returns the position of the first occurrence of a substring. 
              * @param searchString The substring to search for in the string
              * @param position The index at which to begin searching the String object. If omitted, search starts at the beginning of the string.
              */
            indexOf(searchString: string, position?: number): number;

            /**
              * Returns the last occurrence of a substring in the string.
              * @param searchString The substring to search for.
              * @param position The index at which to begin searching. If omitted, the search begins at the end of the string.
              */
            lastIndexOf(searchString: string, position?: number): number;

            /**
              * Determines whether two strings are equivalent in the current locale.
              * @param that String to compare to target string
              */
            localeCompare(that: string): number;

            /** 
            * Matches a string with a regular expression, and returns an array containing the results of that search.
            * @param regexp A variable name or string literal containing the regular expression pattern and flags.
            */
            match(regexp: string): string[];
            /** 
            * Matches a string with a regular expression, and returns an array containing the results of that search.
            * @param regexp A regular expression object that contains the regular expression pattern and applicable flags. 
            */
            match(regexp: RegExp): string[];

            /**
            * Replaces text in a string, using a regular expression or search string.
            * @param searchValue A String object or string literal that represents the regular expression
            * @param replaceValue A String object or string literal containing the text to replace for every successful match of rgExp in stringObj.
            */
            replace(searchValue: string, replaceValue: string): string;
            /**
            * Replaces text in a string, using a regular expression or search string.
            * @param searchValue A String object or string literal that represents the regular expression
            * @param replaceValue A function that returns the replacement text.
            */
            replace(searchValue: string, replaceValue: (substring: string, ...args: any[]) => string): string;
            /**
            * Replaces text in a string, using a regular expression or search string.
            * @param searchValue A Regular Expression object containing the regular expression pattern and applicable flags
            * @param replaceValue A String object or string literal containing the text to replace for every successful match of rgExp in stringObj.
            */
            replace(searchValue: RegExp, replaceValue: string): string;
            /**
            * Replaces text in a string, using a regular expression or search string.
            * @param searchValue A Regular Expression object containing the regular expression pattern and applicable flags
            * @param replaceValue A function that returns the replacement text.
            */
            replace(searchValue: RegExp, replaceValue: (substring: string, ...args: any[]) => string): string;

            /**
            * Finds the first substring match in a regular expression search.
            * @param regexp The regular expression pattern and applicable flags. 
            */
            search(regexp: string): number;
            /**
            * Finds the first substring match in a regular expression search.
            * @param regexp The regular expression pattern and applicable flags. 
            */
            search(regexp: RegExp): number;

            /**
            * Returns a section of a string.
            * @param start The index to the beginning of the specified portion of stringObj. 
            * @param end The index to the end of the specified portion of stringObj. The substring includes the characters up to, but not including, the character indicated by end. 
            * If this value is not specified, the substring continues to the end of stringObj.
            */
            slice(start?: number, end?: number): string;

            /**
            * Split a string into substrings using the specified separator and return them as an array.
            * @param separator A string that identifies character or characters to use in separating the string. If omitted, a single-element array containing the entire string is returned. 
            * @param limit A value used to limit the number of elements returned in the array.
            */
            split(separator: string, limit?: number): string[];
            /**
            * Split a string into substrings using the specified separator and return them as an array.
            * @param separator A Regular Express that identifies character or characters to use in separating the string. If omitted, a single-element array containing the entire string is returned. 
            * @param limit A value used to limit the number of elements returned in the array.
            */
            split(separator: RegExp, limit?: number): string[];

            /**
            * Returns the substring at the specified location within a String object. 
            * @param start The zero-based index number indicating the beginning of the substring.
            * @param end Zero-based index number indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.
            * If end is omitted, the characters from start through the end of the original string are returned.
            */
            substring(start: number, end?: number): string;

            /** Converts all the alphabetic characters in a string to lowercase. */
            toLowerCase(): string;

            /** Converts all alphabetic characters to lowercase, taking into account the host environment's current locale. */
            toLocaleLowerCase(): string;

            /** Converts all the alphabetic characters in a string to uppercase. */
            toUpperCase(): string;

            /** Returns a string where all alphabetic characters have been converted to uppercase, taking into account the host environment's current locale. */
            toLocaleUpperCase(): string;

            /** Removes the leading and trailing white space and line terminator characters from a string. */
            trim(): string;

            /** Returns the length of a String object. */
            length: number;

            // IE extensions
            /**
            * Gets a substring beginning at the specified location and having the specified length.
            * @param from The starting position of the desired substring. The index of the first character in the string is zero.
            * @param length The number of characters to include in the returned substring.
            */
            substr(from: number, length?: number): string;
        }

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        (function () {
            // ... extend the native object and copy over the static properties ...
            System.String = <typeof String><any>function String(value?: any) {
                this.__value = global.String(value);
                //??System.String.prototype.constructor.apply(this, arguments);
                // (IE browsers older than v9 do not populate the string object with the string characters)
                //if (Browser.type == Browser.BrowserTypes.IE && Browser.version <= 8)
                this.length = this.__value.length;
                for (var i = 0; i < this.length; ++i) this[i] = this.charAt(i);
            };
            // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
            Utilities.extend(System.String.$Type, System.Object.$Type); // ('this' is to make sure the primitive Object type is passed in)
            // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
            String.prototype.replaceAll = function replaceAll(replaceWhat: string, replaceWith: string, ignoreCase?: boolean): string {
                return String.replace(this.toString(), replaceWhat, replaceWith, ignoreCase);
            };
            // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
            String.prototype['toValue'] = String.prototype.toString = function toValue(): string { return this.__value; }
                // (NOTE: This is the magic that makes it work, as 'toString()' is called by the other functions to get the string value, and the native implementation only works on a primitive string only.)
            })();

        AppDomain.registerClass(String);
    }

    // =======================================================================================================================

    /** Returns a new array object instance. 
    * Note: This is a DreamSpace system array object, and not the native JavaScript object. */
    export declare function Array<T>(...items: T[]): Array.$Type<T>;
    AppDomain.registerType("Array", [DreamSpace, System]);
    /** Represents an array of items.
    * Note: This is a DreamSpace system array object, and not the native JavaScript object. Because it is not native,
    * manually setting an array item by index past the end will not modify the length property (this may changed as
    * new features are introduce in future EcmaScript versions [such as 'Object.observe()' in ES7]).
    */
    export module Array {
        export declare function isArray(arg: any): boolean;

        export declare class $Type<T> extends Object.$Type implements NativeTypes.IArray<T> {

            constructor(...items: T[]);

            /**
              * Returns a string representation of an array.
              */
            toString(): string;
            toLocaleString(): string;
            /**
              * Combines two or more arrays.
              * @param items Additional items to add to the end of array1.
              */
            concat<U extends T[]>(...items: U[]): T[];
            /**
              * Combines two or more arrays.
              * @param items Additional items to add to the end of array1.
              */
            concat(...items: T[]): T[];
            /**
              * Adds all the elements of an array separated by the specified separator string.
              * @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
              */
            join(separator?: string): string;
            /**
              * Removes the last element from an array and returns it.
              */
            pop(): T;
            /**
              * Appends new elements to an array, and returns the new length of the array.
              * @param items New elements of the Array.
              */
            push(...items: T[]): number;
            /**
              * Reverses the elements in an Array. 
              */
            reverse(): T[];
            /**
              * Removes the first element from an array and returns it.
              */
            shift(): T;
            /** 
              * Returns a section of an array.
              * @param start The beginning of the specified portion of the array.
              * @param end The end of the specified portion of the array.
              */
            slice(start?: number, end?: number): T[];

            /**
              * Sorts an array.
              * @param compareFn The name of the function used to determine the order of the elements. If omitted, the elements are sorted in ascending, ASCII character order.
              */
            sort(compareFn?: (a: T, b: T) => number): T[];

            /**
              * Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
              * @param start The zero-based location in the array from which to start removing elements.
              */
            splice(start: number): T[];

            /**
              * Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
              * @param start The zero-based location in the array from which to start removing elements.
              * @param deleteCount The number of elements to remove.
              * @param items Elements to insert into the array in place of the deleted elements.
              */
            splice(start: number, deleteCount: number, ...items: T[]): T[];

            /**
              * Inserts new elements at the start of an array.
              * @param items  Elements to insert at the start of the Array.
              */
            unshift(...items: T[]): number;

            /**
              * Returns the index of the first occurrence of a value in an array.
              * @param searchElement The value to locate in the array.
              * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.
              */
            indexOf(searchElement: T, fromIndex?: number): number;

            /**
              * Returns the index of the last occurrence of a specified value in an array.
              * @param searchElement The value to locate in the array.
              * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at the last index in the array.
              */
            lastIndexOf(searchElement: T, fromIndex?: number): number;

            /**
              * Determines whether all the members of an array satisfy the specified test.
              * @param callbackfn A function that accepts up to three arguments. The every method calls the callbackfn function for each element in array1 until the callbackfn returns false, or until the end of the array.
              * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
              */
            every(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean;

            /**
              * Determines whether the specified callback function returns true for any element of an array.
              * @param callbackfn A function that accepts up to three arguments. The some method calls the callbackfn function for each element in array1 until the callbackfn returns true, or until the end of the array.
              * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
              */
            some(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean;

            /**
              * Performs the specified action for each element in an array.
              * @param callbackfn  A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array. 
              * @param thisArg  An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
              */
            forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void;

            /**
              * Calls a defined callback function on each element of an array, and returns an array that contains the results.
              * @param callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array. 
              * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
              */
            map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];

            /**
              * Returns the elements of an array that meet the condition specified in a callback function. 
              * @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array. 
              * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
              */
            filter(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): T[];

            /**
              * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
              * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
              * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
              */
            reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue?: T): T;
            /**
              * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
              * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
              * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
              */
            reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;

            /** 
              * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
              * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. 
              * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
              */
            reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue?: T): T;
            /** 
              * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
              * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. 
              * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
              */
            reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;

            /**
              * Gets the length of the array (only). You CANNOT set the array length by setting this value.
              * This is a number one higher than the highest element defined in an array.
              */
            length: number;

            [index: number]: T;
        }

        (function () {
            // ... extend the native object and copy over the static properties ...
            System.Array.$Type = <typeof Array.$Type><any>function Array() {
                System.Object.call(this);
                for (var i = 0, n = arguments.length; i < n; ++i)
                    this.push(arguments[i]);
            };
            // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
            Utilities.extend(System.Array.$Type, System.Object.$Type); // ('this' is to make sure the primitive Object type is passed in)
            // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
            System.Array.isArray = global.Array.isArray;
        })();

        AppDomain.registerClass(Array);
    }

    // =======================================================================================================================
} // (DreamSpace)

// ###########################################################################################################################
